package io.terminus.paas.profiler.utils

import com.alibaba.dubbo.common.Constants
import com.alibaba.dubbo.common.URL
import com.alibaba.dubbo.common.logger.LoggerFactory
import com.alibaba.dubbo.common.utils.NetUtils
import com.alibaba.dubbo.common.utils.StringUtils
import com.alibaba.dubbo.registry.NotifyListener
import com.alibaba.dubbo.registry.RegistryService
import org.springframework.beans.factory.DisposableBean
import org.springframework.beans.factory.InitializingBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
import java.util.concurrent.atomic.AtomicLong

/**
 * Created by gengrong on 16/3/16.
 *
 * Copy于Dubbo-admin中的RegistryServerSync
 * 语法修改至Kotlin,替换Tool外未做任何修改
 *
 *
 * 由于其缓存结构,查询较为不便,后期可能进行处理
 */
//@Service
class RegistryServerSync @Autowired constructor(
        private val registryService: RegistryService) : NotifyListener {

    // ConcurrentMap<category, ConcurrentMap<servicename, Map<Long, URL>>>
    val registryCache: ConcurrentMap<String, ConcurrentMap<String, Map<Long, URL>>> = ConcurrentHashMap()

    init {
        registryService.subscribe(SUBSCRIBE, this)
    }

    //    @Throws(Exception::class)
    //    override fun destroy() {
    //        registryService!!.unsubscribe(SUBSCRIBE, this)
    //    }

    // 收到的通知对于 ，同一种类型数据（override、subcribe、route、其它是Provider），同一个服务的数据是全量的
    override fun notify(urls: List<URL>?) {
        if (urls == null || urls.isEmpty()) {
            return
        }
        // Map<category, Map<servicename, Map<Long, URL>>>
        val categories = hashMapOf<String, MutableMap<String, MutableMap<Long, URL>>>()
        for (url in urls) {
            val category = url.getParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY)
            if (Constants.EMPTY_PROTOCOL.equals(url.protocol, ignoreCase = true)) {
                // 注意：empty协议的group和version为*
                val services = registryCache[category]
                if (services != null) {
                    val group = url.getParameter(Constants.GROUP_KEY)
                    val version = url.getParameter(Constants.VERSION_KEY)
                    // 注意：empty协议的group和version为*
                    if (Constants.ANY_VALUE != group && Constants.ANY_VALUE != version) {
                        services.remove(url.serviceKey)
                    } else {
                        for (serviceEntry in services.entries) {
                            val service = serviceEntry.key
                            if (DubboTool.getInterface(service).equals(url.serviceInterface)
                                    && (Constants.ANY_VALUE == group || StringUtils.isEquals(group, DubboTool.getGroup(service)))
                                    && (Constants.ANY_VALUE == version || StringUtils.isEquals(version, DubboTool.getVersion(service)))) {
                                services.remove(service)
                            }
                        }
                    }
                }
            } else {
                var services: MutableMap<String, MutableMap<Long, URL>>? = categories[category]
                if (services == null) {
                    services = hashMapOf<String, MutableMap<Long, URL>>()
                    categories.put(category, services)
                }
                val service = url.serviceKey
                var ids: MutableMap<Long, URL>? = services[service]
                if (ids == null) {
                    ids = hashMapOf<Long, URL>()
                    services.put(service, ids)
                }
                ids.put(ID.incrementAndGet(), url)
            }
        }
        for (categoryEntry in categories.entries) {
            val category = categoryEntry.key
            var services: ConcurrentMap<String, Map<Long, URL>>? = registryCache[category]
            if (services == null) {
                services = ConcurrentHashMap<String, Map<Long, URL>>()
                registryCache.put(category, services)
            }
            services.putAll(categoryEntry.value)
        }
    }

    companion object {

        private val logger = LoggerFactory.getLogger(RegistryServerSync::class.java)

        private val SUBSCRIBE = URL(Constants.ADMIN_PROTOCOL, NetUtils.getLocalHost(), 0, "",
                Constants.INTERFACE_KEY, Constants.ANY_VALUE,
                Constants.GROUP_KEY, Constants.ANY_VALUE,
                Constants.VERSION_KEY, Constants.ANY_VALUE,
                Constants.CLASSIFIER_KEY, Constants.ANY_VALUE,
                Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY + ","
                + Constants.CONSUMERS_CATEGORY + ","
                + Constants.ROUTERS_CATEGORY + ","
                + Constants.CONFIGURATORS_CATEGORY,
                Constants.ENABLED_KEY, Constants.ANY_VALUE,
                Constants.CHECK_KEY, false.toString())

        private val ID = AtomicLong()
    }
}
